//
// File:    bte_coll_mmap.C
// Author:  Octavian Procopiuc <tavi@cs.duke.edu>
//          (using some code by Rakesh Barve)
//
// BTE_collection_mmap implementation.
//

#include <versions.H>
VERSION(bte_coll_mmap_C, "$Id: bte_coll_mmap.C,v 1.7 2002/08/01 00:40:54 tavi Exp $");

// For enabling/disabling logging.
#include "lib_config.H"

#include <bte_coll_mmap.H>

extern "C" {
  // For errno.
#include <errno.h>
  // For strerror().
#include <string.h>
  // For mmap.
#include <sys/mman.h>
int ftruncate(int fd, off_t length);
}

BTE_err BTE_collection_mmap::get_block_internals(bid_t bid, void * &place) {

  place = mmap(NULL, header_.block_size,
	       read_only_ ? PROT_READ : 
	       PROT_READ | PROT_WRITE, 
#ifdef SYSTYPE_BSD
	       MAP_FILE | MAP_VARIABLE | MAP_NOSYNC |
#endif
	       MAP_SHARED, bcc_fd_, bid_to_file_offset(bid));

  if (place == (void *)(-1)) {
    LOG_FATAL_ID("mmap() failed to map in a block from file.");
    LOG_FATAL_ID(strerror(errno));
    return BTE_ERROR_MEMORY_ERROR;
  }

  //  madvise(place, header_.block_size, MADV_RANDOM);

  // Register the memory allocation since mmapped memory is
  // not accounted for otherwise.
  register_memory_allocation(header_.block_size);

  in_memory_blocks_++;
  return BTE_ERROR_NO_ERROR;
}


BTE_err BTE_collection_mmap::put_block_internals(bid_t bid, void* place, char dirty) {
  
  // The dirty parameter is not used in this implemetation.

  if ((bid <= 0) || (bid >= header_.last_block)) {
    LOG_FATAL_ID("Incorrect bid in placeholder.");
    return BTE_ERROR_INVALID_PLACEHOLDER;
  }

#if (BTE_COLLECTION_MMAP_LAZY_WRITE < 2)
  if (!read_only_) {
    if (msync((char*)place, header_.block_size, 
#  if (BTE_COLLECTION_MMAP_LAZY_WRITE == 1)
	      MS_ASYNC
#  else
	      MS_SYNC
#  endif
	      ) == -1) {
      LOG_FATAL_ID("Failed to msync() block to file.");
      LOG_FATAL_ID(strerror(errno));
      return BTE_ERROR_IO_ERROR;
    }    
  }
#endif

  if (munmap((char*)place, header_.block_size) == -1) {
    LOG_FATAL_ID("Failed to unmap() block of file.");
    LOG_FATAL_ID(strerror(errno));
    return BTE_ERROR_IO_ERROR;
  }

  register_memory_deallocation(header_.block_size);

  in_memory_blocks_--;
  return BTE_ERROR_NO_ERROR;
}
 

BTE_err BTE_collection_mmap::sync_block(bid_t bid, void* place, char dirty) {

  if ((bid <= 0) || (bid >= header_.last_block)) {
    LOG_FATAL_ID("Incorrect bid in placeholder.");
    return BTE_ERROR_INVALID_PLACEHOLDER;
  }
  
  if (!read_only_) {
    if (msync((char*)place, header_.block_size, MS_SYNC)) {
      LOG_FATAL_ID("Failed to msync() block to file.");
      LOG_FATAL_ID(strerror(errno));
      return BTE_ERROR_IO_ERROR;
    }
  }

  stats_.record(BLOCK_SYNC);
  gstats_.record(BLOCK_SYNC);
  return BTE_ERROR_NO_ERROR;
}
